package com.white.commonlib.adapter.recycle;

import android.content.Context;
import android.support.annotation.LayoutRes;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


import java.util.List;

/**
 * Created by ytf on 2017/3/31 031.<br/>
 * Description: <br/>
 * recycleView的适配器，支持加载更多，如果不想用加载更多，可以重写<a>{@link RecycleBaseAdapter#needLoadMoreSupport()}<a/>返回false即可。<br/>
 * 支持多种布局显示，需要重写三个方法<br/>
 * <ul>
 * <li>
 * 重写<a>{@link RecycleBaseAdapter#getCustomViewType(int)}<a/>根据不同位置返回不同类型标识(加载更多的viewType是整型最大值，自定类型时不能占用这个数)
 * </li>
 * <li>
 * 重写<a>{@link RecycleBaseAdapter#getCustomView(int) }()<a/>返回不同类型对应的view布局
 * </li>
 * <li>
 * 重写<a>{@link RecycleBaseAdapter#getCustomHolder(Context, ViewGroup, int, View)}()<a/>根据不同viewType返回不同的ViewHolder
 * </li>
 * </ul>
 * 加载更多视图上的状态变化需要根据<a>{@link OnLoadMoreListener#loadMore()}</a>由调用者根据加载成功与否调用适配器的相关方法<br/>
 * <ul>
 *     <li>正在加载<a>{@link RecycleBaseAdapter#setOnLoadingMore()}</a></li>
 *     <li>加载成功<a>{@link RecycleBaseAdapter#setLoadSuccess()}</a></li>
 *     <li>加载失败<a>{@link RecycleBaseAdapter#setLoadFailed()}</a></li>
 *     <li>没有更多数据<a>{@link RecycleBaseAdapter#setDataDrain()}</a></li>
 *     <li>恢复默认状态<a>{@link RecycleBaseAdapter#setStateDefault()}</a></li>
 * </ul>
 */

public abstract class RecycleBaseAdapter<T extends Object> extends RecyclerView.Adapter
{
    protected Context mContext;
    protected List<T> data;
    private final int MORE_TYPE = Integer.MAX_VALUE;
    private final int HEADER_TYPE = Integer.MIN_VALUE;
    private int layoutManagerType;
    private LinearLayoutManager linearLayoutManager;
    private GridLayoutManager gridLayoutManager;
    private StaggeredGridLayoutManager staggeredGridLayoutManager;

    public static final int TYPE_LINEAR = 0;
    public static final int TYPE_GRID = 1;
    public static final int TYPE_STAGGERED = 2;

    //数据集没超过屏幕不显示加载更多处理
    private boolean dataNotFull;

    public RecycleBaseAdapter(Context context, List<T> data)
    {
        mContext = context;
        this.data = data;
    }

    @Override
    public void onViewAttachedToWindow(RecyclerView.ViewHolder holder)
    {
        super.onViewAttachedToWindow(holder);
        //设置瀑布流布局加载更多的布局需要占用一行
        if (layoutManagerType == TYPE_STAGGERED)
        {
            ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
            if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams)
            {
                StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
                p.setFullSpan(holder.getLayoutPosition() >= data.size());
            }
        }
    }


    @Override
    public void onAttachedToRecyclerView(RecyclerView rv)
    {
        super.onAttachedToRecyclerView(rv);
        if (rv.getLayoutManager() == null)
            throw new IllegalArgumentException("LayoutManager can't be null");
        RecyclerView.LayoutManager manager = rv.getLayoutManager();
        if (manager instanceof GridLayoutManager)
        {
            layoutManagerType = TYPE_GRID;
            gridLayoutManager = (GridLayoutManager) manager;
            //设置网格布局加载更多的布局需要占用一行
            gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup()
            {
                @Override
                public int getSpanSize(int position)
                {
                    return position >= data.size() ? gridLayoutManager.getSpanCount() : 1;
                }
            });
        } else if(manager instanceof LinearLayoutManager)
        {
            //此处把线性布局放到这里判断，原因是GridLayoutManager继承自LinearLayoutManager
            layoutManagerType = TYPE_LINEAR;
            linearLayoutManager = (LinearLayoutManager) manager;
        }else if (manager instanceof StaggeredGridLayoutManager)
        {
            layoutManagerType = TYPE_STAGGERED;
            staggeredGridLayoutManager = (StaggeredGridLayoutManager) manager;
        }
        //添加滑动监听，监听是否需要显示加载更多布局
        rv.addOnScrollListener(new RecyclerView.OnScrollListener()
        {
            @Override
            public void onScrollStateChanged(RecyclerView recyclerView, int newState)
            {
                super.onScrollStateChanged(recyclerView, newState);
            }

            @Override
            public void onScrolled(RecyclerView recyclerView, int dx, int dy)
            {
                super.onScrolled(recyclerView, dx, dy);
                //需要加载更多才处理该逻辑
                if(needLoadMoreSupport())
                {
                    //如果滑动到数据集的最后一个
                    int lastPosiAccured = recyclerView.getAdapter().getItemCount();
//                    if(isHeaderAndMoreSuppport())
//                    {
//                        lastPosiAccured = data.size();
//                    }else
//                    {
//                        lastPosiAccured = data.size() - 1;
//                    }
                    if(lastVisiPosition == lastPosiAccured)
                    {
                        //置为-1是为了避免重入打乱逻辑，因为currentPosition只有在最后一个位置的时候才会被赋值
                        lastVisiPosition = -1;
                        //在滑动的过程中计算当前item的数量是否占用了一屏，如果没有则不显示加载更多布局也不回调，否则就显示
                        int lastVisiblePosition = getLastVisiblePosition();
                        if(layoutManagerType == TYPE_LINEAR  || layoutManagerType == TYPE_STAGGERED)
                        {
                            dataNotFull = lastVisiblePosition == lastPosiAccured;
                        }else if(layoutManagerType == 1)
                        {
                            dataNotFull = lastVisiblePosition-1 == lastPosiAccured;
                        }
//                    LogManager.getInstance().e("s", "dataNotFull = " + dataNotFull + "-----lastVisiblePosition = " + lastVisiblePosition + "---dataSize = " + data.size());
                    }
                }
            }
        });
    }

    private boolean isHeaderAndMoreSuppport()
    {
        return needHeader() && needLoadMoreSupport();
    }

    /**
     * 获取最后一条展示的位置
     *
     * @return
     */
    private int getLastVisiblePosition()
    {
        int position = 0;
        switch (layoutManagerType)
        {
            case TYPE_LINEAR:
                position = linearLayoutManager.findLastCompletelyVisibleItemPosition();
                break;
            case TYPE_GRID:
                position = gridLayoutManager.findLastCompletelyVisibleItemPosition();
                break;
            case TYPE_STAGGERED:
                int[] lastPositions = staggeredGridLayoutManager
                        .findLastCompletelyVisibleItemPositions(new int[staggeredGridLayoutManager.getSpanCount()]);
                position = getMaxPosition(lastPositions);
                break;
        }
        return position;
    }

    /**
     * 获得最大的位置
     *
     * @param positions
     * @return
     */
    private int getMaxPosition(int[] positions)
    {
        int size = positions.length;
        int maxPosition = Integer.MIN_VALUE;
        for (int i = 0; i < size; i++)
        {
            maxPosition = Math.max(maxPosition, positions[i]);
        }
        return maxPosition;
    }

    /***
     * 是否需要支持加载更多，默认返回true
     * @return
     */
    public boolean needLoadMoreSupport()
    {
        return true;
    }

    /***
     * 是否支持header 默认false
     * @return
     */
    public boolean needHeader()
    {
        return false;
    }

    @Override
    public long getItemId(int position)
    {
        return position;
    }

    @Override
    public int getItemCount()
    {
        if(data == null)
            return 0;
        int sz = data.size();
        if (needLoadMoreSupport() && !needHeader())
        {
            if(sz == 0)
                return 0;
            return sz + 1;
        }else if(!needLoadMoreSupport() && needHeader())
        {
            if(sz == 0)
                return 1;
            return sz + 1;
        }else if(needLoadMoreSupport() && needHeader())
        {
            if(sz == 0)
                return 1;
            return sz + 2;
        }else
        {
            return sz;
        }
    }

    @Override
    public int getItemViewType(int position)
    {
        if(position == 0)
        {
            if(needHeader())
            {
                return HEADER_TYPE;
            }else
            {
                return getCustomViewType(position);
            }
        }else if (position == data.size())
        {
            if(needLoadMoreSupport() && !needHeader())
            {
                return MORE_TYPE;
            }else
            {
                return getCustomViewType(position);
            }
        }else if(position > data.size())
        {
            return MORE_TYPE;
        }else
        {
            return getCustomViewType(position);
        }
    }

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType)
    {
        if (viewType == MORE_TYPE)
        {
            //这里也进行判断是用于第一次创建moreholder时是否要显示加载更多
            int lastVisiblePosition = getLastVisiblePosition();
            dataNotFull = lastVisiblePosition == data.size() - 1;
            View v = LayoutInflater.from(mContext).inflate(getLoadMoreView(), parent, false);
            return getMoreHolder(parent, v);
        }else if(viewType == HEADER_TYPE)
        {
            View v = LayoutInflater.from(mContext).inflate(getHeaderView(), parent, false);
            return getHeaderHolder(mContext, parent, v);
        }else
        {
            View v = LayoutInflater.from(mContext).inflate(getCustomView(viewType), parent, false);
            return getCustomHolder(mContext, null, viewType, v);
        }
    }

    /***
     * 根据位置返回不同的viewType，默认返回0，如果要支持多种view，根据position返回
     * @param position
     * @return
     */
    public int getCustomViewType(int position)
    {
        return 0;
    }

    /***
     * 根据viewType的类型返回不同的viewholder, viewType是getCustomViewType根据需求返回的，默认返回0(加上loadmore总共两种viewType)
     * @param context
     * @param parent
     * @param viewType
     * @param v
     * @return
     */
    public abstract RecyclerView.ViewHolder getCustomHolder(Context context, ViewGroup parent, int viewType, View v);

    /***
     * 根据viewType不同返回不同的viewholder布局id
     * @param viewType
     * @return
     */
    public abstract @LayoutRes int getCustomView(int viewType);

    /***
     * 返回Header布局id
     * @return
     */
    public @LayoutRes int getHeaderView()
    {
        return 0;
    }

    /***
     * 默认是支持加载更多，所以需要提供加载更多的viewholder，如果重写了needLoadMoreSupport并返回false(不允许加载更多)，那么这里可以返回null
     * @param parent
     * @return
     */
    public abstract BaseLoadMoreViewHolder getMoreHolder(ViewGroup parent, View v);

    /***
     * 返回加载更多布局id
     * @return
     */
    public abstract @LayoutRes int getLoadMoreView();

    /***
     * 默认是支持加载更多，所以需要提供加载更多的viewholder，如果重写了needLoadMoreSupport并返回false(不允许加载更多)，那么这里可以返回null
     *
     * @param mContext
     * @param parent
     * @return
     */
    public BaseHeaderViewHolder getHeaderHolder(Context mContext, ViewGroup parent, View v)
    {
        return null;
    }

    protected OnLoadMoreListener loadMoreListener;

    /***
     * 设置加载更多的监听
     * @param l
     */
    public void setOnLoadMoreListener(OnLoadMoreListener l)
    {
        this.loadMoreListener = l;
    }

    public static final int LOADING = 0;
    public static final int DEFAULT = 1;
    public static final int FAILED = 2;
    public static final int DATA_DRAIN = 3;

//    @IntDef({LOADING, DEFAULT, FAILED, DATA_DRAIN})
//    @Retention(RetentionPolicy.SOURCE)
//    private @interface State{}

    private int state = DEFAULT;

    private BaseLoadMoreViewHolder mh;

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position)
    {
        if (holder instanceof BaseLoadMoreViewHolder)
        {
            //如果数据没有占满屏幕，则不显示加载更多，也不回调直接返回
            mh = (BaseLoadMoreViewHolder) holder;
            int lastVisiblePosition = getLastVisiblePosition();
            if(isHeaderAndMoreSuppport())
            {
                dataNotFull = lastVisiblePosition == data.size();
            }else
            {
                dataNotFull = lastVisiblePosition == data.size() - 1;
            }
            if (dataNotFull)
            {
                mh.getItemView().setVisibility(View.GONE);
                return;
            } else
            {
                mh.getItemView().setVisibility(View.VISIBLE);
            }
            mh.onStartLoaddingMore();
            mh.onLoadingMore();

            if(state != FAILED && state != DATA_DRAIN)
            {
                if(state != LOADING)
                {
                    state = LOADING;
                    if (loadMoreListener != null)
                    {
                        loadMoreListener.loadMore();
                    }
                }
            }else if(state == FAILED)
            {
                setLoadFailed();
            }else
            {
                setDataDrain();
            }
        }else if(holder instanceof BaseHeaderViewHolder)
        {
            BaseHeaderViewHolder header = (BaseHeaderViewHolder) holder;
//            header.setIsRecyclable(false);
            header.setContent(mContext);
        }else if(holder instanceof BaseViewHolder)
        {
            BaseViewHolder bh = (BaseViewHolder) holder;
            //瀑布流布局动态设置holder的高度。待处理
//            if(layoutManagerType == 2)
//            {
//                ViewGroup.LayoutParams lp = holder.itemView.getLayoutParams();
//                if (lp != null && lp instanceof StaggeredGridLayoutManager.LayoutParams)
//                {
//                    StaggeredGridLayoutManager.LayoutParams p = (StaggeredGridLayoutManager.LayoutParams) lp;
//
//                }
//            }
            int pos = bh.getAdapterPosition();
            int listPos;
            if((needLoadMoreSupport() && needHeader()) ||
                    (!needLoadMoreSupport() && needHeader()))
            {
                listPos = pos - 1;
            }else
            {
                listPos = pos;
            }

            T d = data.get(listPos);
            listenViewClick(bh);
            bh.setData(d, listPos);
            if(needHeader())
            {
                if(pos == data.size())
                {
                    lastVisiPosition = pos;
                }
            }else
            {
                if(pos == data.size() - 1)
                {
                    lastVisiPosition = pos;
                }
            }
        }
    }

    /**用来判断数据是否占满全屏*/
    private int lastVisiPosition;

    /***
     * 回调给适配器的方法，加载成功
     */
    public void setLoadSuccess()
    {
        state = DEFAULT;
        if (mh != null)
            mh.onLoadSuccess();
    }

    /***
     * 回调给适配器的方法，状态恢复默认
     */
    public void setStateDefault()
    {
        state = DEFAULT;
    }

    /***
     * 回调给适配器的方法，正在加载
     */
    public void setOnLoadingMore()
    {
        state = LOADING;
        if (mh != null)
            mh.onLoadingMore();
    }

    public int getCurrentState()
    {
        return state;
    }

    /***
     * 回调给适配器的方法，加载失败
     */
    public void setLoadFailed()
    {
        state = FAILED;
        if (mh != null)
            mh.onLoadFailed();
    }

    /***
     * 回调给适配器的方法，没有更多数据可以加载
     */
    public void setDataDrain()
    {
        state = DATA_DRAIN;
        if (mh != null)
            mh.onDataDrain();
    }

    private void listenViewClick(final BaseViewHolder bh)
    {
        if (itemClickListener != null)
        {
            bh.getItemView().setOnClickListener(new View.OnClickListener()
            {
                @Override
                public void onClick(View v)
                {
                    int posi = bh.getAdapterPosition();
                    if(needHeader())
                    {
                        posi = posi - 1;
                    }
                    itemClickListener.onItemClick(v, posi, posi);
                }
            });
        }

        if (itemLongClickListener != null)
        {
            bh.getItemView().setOnLongClickListener(new View.OnLongClickListener()
            {
                @Override
                public boolean onLongClick(View v)
                {
                    int posi = bh.getAdapterPosition();
                    if(needHeader())
                    {
                        posi = posi - 1;
                    }
                    itemLongClickListener.onItemLongClick(v, posi, posi);
                    return true;
                }
            });
        }
    }

    private OnItemClickListener itemClickListener;
    private OnItemLongClickListener itemLongClickListener;

    /***
     * 设置item点击监听
     * @param l
     */
    public void setOnItemClickListener(OnItemClickListener l)
    {
        itemClickListener = l;
    }

    /***
     * 设置item长按监听
     * @param l
     */
    public void setOnItemLongClickListener(OnItemLongClickListener l)
    {
        itemLongClickListener = l;
    }

    public interface OnItemClickListener
    {
        void onItemClick(View view, int position, long id);
    }

    public interface OnItemLongClickListener
    {
        public boolean onItemLongClick(View view, int position, long id);
    }
}
